package com.unidbg.util;


import com.github.unidbg.Module;
import com.github.unidbg.arm.ARMEmulator;
import com.github.unidbg.linux.android.AndroidARMEmulator;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.memory.Memory;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

public class TestJni extends AbstractJni {
    // ARM模拟器
    private final ARMEmulator emulator;
    // vm
    private final VM vm;
    // 载入的模块
    private final Module module;

    private final DvmClass TTEncryptUtils;

    /**
     *
     * @param soFilePath   需要执行的so文件路径
     * @param classPath    需要执行的函数所在的Java类路径
     * @throws IOException
     */
    public TestJni(String soFilePath, String classPath) throws IOException {
        // 创建app进程，包名可任意写
        emulator = new AndroidARMEmulator("io.liuliu.music");
        Memory memory = emulator.getMemory();
        // 作者支持19和23两个sdk
        memory.setLibraryResolver(new AndroidResolver(23));
        // 创建DalvikVM，利用apk本身，可以为null
        vm = ((AndroidARMEmulator) emulator).createDalvikVM(null);
        vm.setVerbose(true);
        vm.setJni(this);
        // （关键处1）加载so，填写so的文件路径
        DalvikModule dm = vm.loadLibrary(new File(soFilePath), false);
        // 调用jni
        dm.callJNI_OnLoad(emulator);
        module = dm.getModule();
        // （关键处2）加载so文件中的哪个类，填写完整的类路径
        TTEncryptUtils = vm.resolveClass(classPath);
    }

    /**
     * 调用so文件中的指定函数
     * @param methodSign 传入你要执行的函数信息，需要完整的smali语法格式的函数签名
     * @param args       是即将调用的函数需要的参数
     * @return 函数调用结果
     */
    private String myJni(String methodSign, Object ...args) {
        // 使用jni调用传入的函数签名对应的方法（）
        Object value = TTEncryptUtils.callStaticJniMethodObject(emulator, methodSign, args).getValue();
        return value.toString();
    }

    /**
     * 关闭模拟器
     * @throws IOException
     */
    private void destroy() throws IOException {
        emulator.close();
        System.out.println("emulator destroy...");
    }

    public static String main1(String[] args) throws IOException {
        // 1、需要调用的so文件所在路径
        String soFilePath = "C:\\Users\\Administrator\\Desktop/libtalaccsecurity.so";
        // 2、需要调用函数所在的Java类完整路径，比如a/b/c/d等等，注意需要用/代替.
        String classPath = "com/tal/user/fusion/util/JNISecurity";
        // 3、需要调用方法,再jadx中找到对应的方法，然后点击下面的Smail,复制方法的Smail代码。
        String methodSign = "sign(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
        TestJni testJni = new TestJni(soFilePath, classPath);
        // 输出getGameKey方法调用结果
        String data=testJni.myJni(methodSign,args[0],args[1]);
        System.out.println("================================");
        System.out.println("时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        System.out.println("================================");
        System.out.println("参数列表:"+Arrays.toString(args));
        System.err.println("加密密结果:"+data);
        System.out.println("================================");
        testJni.destroy();
        return data;
    }
    public static String main2(String soFilePath,String classPath,String methodSign,Object ...args) throws IOException {
        // 1、需要调用的so文件所在路径
        // 2、需要调用函数所在的Java类完整路径，比如a/b/c/d等等，注意需要用/代替.
        // 3、需要调用方法,再jadx中找到对应的方法，然后点击下面的Smail,复制方法的Smail代码。
        TestJni testJni = new TestJni(soFilePath, classPath);
        // 输出getGameKey方法调用结果
        String data=testJni.myJni(methodSign,args);
        System.out.println("================================");
        System.out.println("时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        System.out.println("================================");
        System.out.println("参数列表:"+Arrays.toString(args));
        System.out.println("加密密结果:"+data);
        System.out.println("================================");
        testJni.destroy();
        return data;
    }

}